package com.wang.tool.valve;

import com.alibaba.fastjson.JSONObject;
import com.wang.tool.monitor.InvokeTemplate;
import com.wang.tool.util.SimpleLogUtil;
import com.wang.tool.util.CommonUtil;
import com.wang.tool.valve.strategy.JsonpathValve;
import com.wang.tool.valve.strategy.RangeValve;
import com.wang.tool.valve.strategy.RegexValve;
import com.wang.tool.valve.strategy.SimpleValve;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * @Description 阀门通过策略适配器
 * 如要自实现策略
 * 实现Valve+注册入ValveAdapter
 * 功能上管理阀门策略,可以理解为阀门策略工厂
 * 目的是让使用者处理阀门逻辑时,可只关注逻辑而不用关注具体策略
 * @Author shaopeng
 * @Date 2021/7/21
 * @Version 1.0
 */
public class ValveAdapter {
    /**
     * 策略
     */
    public static final String KEY_STRATEGY = "strategy";

    /**
     * 类型缓存
     */
    private static Map<String, Class<? extends Valve>> code2StrategyType = new HashMap<>();

    static {
        //特性策略注册
        register(RangeValve.STRATEGY, RangeValve.class);
        register(RegexValve.STRATEGY, RegexValve.class);
        register(JsonpathValve.STRATEGY, JsonpathValve.class);
    }


    /**
     * 解析配置
     * 通过json的 strategy key 判断使用那种类型解析
     *
     * @param configJson
     * @return 非空
     * @throws IllegalArgumentException 参数不合
     */
    public static Valve parseConfig2Valve(JSONObject configJson) throws IllegalArgumentException {
        if (configJson == null) {
            return new SimpleValve();
        }
        return JSONObject.parseObject(configJson.toJSONString(), findStrategyType(configJson.getString(KEY_STRATEGY)));
    }

    /**
     * 注册策略
     * 不允许变更
     *
     * @param type
     */
    public static synchronized void register(String strategy, Class<? extends Valve> type) {
        if (strategy == null || type == null) {
            return;
        }
        if (CommonUtil.isBlank(strategy)) {
            throw new IllegalArgumentException("valve strategy code can not be null");
        }
        if (code2StrategyType.containsKey(strategy)) {
            Class<? extends Valve> oldType = code2StrategyType.get(strategy);
            if (Objects.equals(type, oldType)) {
                return;
            }
            throw new IllegalArgumentException("valve strategy code is exist strategy:" + strategy + ", type:" + oldType.getName());
        }
        code2StrategyType.put(strategy, type);
        SimpleLogUtil.info("[registerValveStrategy] strategy:{0}, type:{1}", strategy, type);
    }


    /**
     * 获取适配的模型类
     *
     * @param strategy
     * @return 非空
     * @throws IllegalArgumentException strategy 不支持
     */
    public static Class<? extends Valve> findStrategyType(String strategy) throws IllegalArgumentException {
        if (CommonUtil.isBlank(strategy)) {
            return SimpleValve.class;
        }
        if (code2StrategyType.containsKey(strategy)) {
            return code2StrategyType.get(strategy);
        }
        throw new IllegalArgumentException("unknown valve strategy:" + strategy);
    }

    /**
     * 新Valve替换老Valve
     * 如果新阀门有效则返回新阀门,其余返回老阀门
     *
     * @param newValve 新阀门
     * @param oldValve 老阀门
     * @return
     */
    public static Valve tryReplace(Valve newValve, Valve oldValve) {
        String name = oldValve instanceof ValveAgent ? ((ValveAgent) oldValve).getName() : null;
        return InvokeTemplate.tryReplace(name, oldValve, () -> {
            if (newValve == null) {
                return oldValve;
            }
            newValve.prepare();
            return newValve;
        });
    }
}
